package org.qiyu.live.im.core.server.starter;

import cn.hutool.core.util.StrUtil;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import jakarta.annotation.Resource;
import org.qiyu.live.im.core.server.ImCoreServerApplication;
import org.qiyu.live.im.core.server.common.ChannelHandlerContextCache;
import org.qiyu.live.im.core.server.common.TcpImDecoder;
import org.qiyu.live.im.core.server.common.TcpImEncoder;
import org.qiyu.live.im.core.server.handler.ImServerCoreHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: sfx
 * Date: 2023-10-08
 * Time: 20:01
 */
@Configuration
public class NettyImServerStarter implements InitializingBean {

    private Logger LOGGER = LoggerFactory.getLogger(ImCoreServerApplication.class);

    @Resource
    private ImServerCoreHandler imServerCoreHandler;

    // 端口
    @Value("${qiyu.im.tcp.port}")
    private int port;

    @Resource
    private Environment environment;

    /**
     * 基于netty启动一个Java进程
     */
    public void startApplication() throws InterruptedException {
        // 1. 设置端口号
        // 2. 注册线程组
        // 2.1 接收accept事件
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        // 2.2 接收read&write事件
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workerGroup);
        // 设置channel
        bootstrap.channel(NioServerSocketChannel.class);

        // 3. 初始化netty相关handler
        bootstrap.childHandler(new ChannelInitializer<>() {
            @Override
            protected void initChannel(Channel ch) throws Exception {
                LOGGER.info("初始化通道成功 port={}", port);
                // 增加编码器 + 解码器
                ch.pipeline().addLast(new TcpImDecoder());
                ch.pipeline().addLast(new TcpImEncoder());
                // 设置netty相关的handler
                ch.pipeline().addLast(imServerCoreHandler);
            }
        });

        // 钩子回调,进行优雅关机
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }));

        // 服务一启动的时候,我们要保存着服务的IP + 端口
        // - DUBBO_PORT_TO_REGISTRY=192.168.238.128 - DUBBO_PORT_TO_BIND=9099
        String registryIP = "192.168.61.104";
        String registryPort = "9099";
        if (StrUtil.isEmpty(registryIP) || StrUtil.isEmpty(registryPort)) {
            throw new IllegalArgumentException("registryIP  registryPort 参数为空");
        }

        ChannelHandlerContextCache.setImCoreServerAddress(registryIP + ":" + registryPort);
        // 4. 实现监听->同步阻塞
        ChannelFuture channelFuture = bootstrap.bind(port).sync();
        LOGGER.info("服务启动成功 port={}", port);
        channelFuture.channel().closeFuture().sync();
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Thread nettyServerThread = new Thread(() -> {
            try {
                startApplication();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        nettyServerThread.setName("qiyu-im-server");
        nettyServerThread.start();
    }
}